import { Box3, Frustum, MathUtils, Matrix4, PerspectiveCamera, Ray, Sphere, Vector3 } from "three";
import Config from "../Config";
import Ellipsoid from "../math/Ellipsoid";

export default class CameraUtil {

    public static updateCameraMatrix(camera){
         // 更新相机矩阵（关键步骤！）
        camera.updateMatrix();
        camera.updateMatrixWorld(true);
        camera.updateWorldMatrix(true, true);
        camera.updateProjectionMatrix();
    }

    /**检查包围盒或者包围球是否在相机的视椎体内 */
    public static checkVisible(boundingVolume: Sphere | Box3, camera: PerspectiveCamera): boolean {
        // 计算视锥体投影矩阵
        const projectionMatrix = new Matrix4().multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse
        );

        // 创建视锥体对象
        const frustum = new Frustum();
        frustum.setFromProjectionMatrix(projectionMatrix);

        let isIntersect = false;
        if (boundingVolume instanceof Box3) {
            isIntersect = frustum.intersectsBox(boundingVolume);
        } else if (boundingVolume instanceof Sphere) {
            isIntersect = frustum.intersectsSphere(boundingVolume);
        }

        return isIntersect;
    }

    public static checkCover(tileSpher: Sphere, camera: PerspectiveCamera): boolean {
        // 思路：计算出瓦片包围球到相机位置最近的点a，首先确保点a在地球上，然后点a再顺着到地球球心的向量移动0.1（避免a在地球上会影响后边的步骤），从点a到相机位置构造一条向量A，计算出向量A是否和地球椭球有相交点，如果没有相交点就说明瓦片没有被遮挡，否则，瓦片被遮挡
        let ellipsoid: Ellipsoid = Config.Ellipsoid;
        let cameraPoint = camera.position.clone();
        let vectorFromTileToCamera = cameraPoint.clone().sub(tileSpher.center).normalize();
        let ray: Ray = new Ray(tileSpher.center, vectorFromTileToCamera);
        let closetPointA = new Vector3(); //从瓦片包围球到相机位置最近的点

        closetPointA = ray.intersectSphere(tileSpher, closetPointA);
        let vectorFromClosePointAtoCenter = closetPointA.clone().sub(ellipsoid.center).normalize();
        ray = new Ray(closetPointA, vectorFromClosePointAtoCenter);
        let intersectionArray = ellipsoid.intersectRay(ray);
        if(intersectionArray && intersectionArray.length >= 1){
            closetPointA = intersectionArray[0];
            closetPointA = closetPointA.add(vectorFromClosePointAtoCenter.multiplyScalar(0.1));
        }

        let vectorA = cameraPoint.clone().sub(closetPointA).normalize();
        let rayA = new Ray(closetPointA, vectorA);
        intersectionArray = ellipsoid.intersectRay(rayA);
         if((intersectionArray == null || intersectionArray.length == 0)){
            return true
        }
        return false;
    }

     /**检测瓦片是否被地球遮挡 */
    public static checkCover3(tileSpher: Sphere, camera: PerspectiveCamera): boolean {
        // //思路：计算出瓦片包围球到相机位置最近的点a，从地球球心到点a到构造一条向量A，从地球球心到相机位置构造一条向量B，求出A和B之间的夹角，如果夹角大于90度就是被遮挡，反之，没有被遮挡
        let cameraPoint = camera.position.clone();
        // let vectorFromTileToCamera = cameraPoint.clone().sub(tileSpher.center).normalize();
        // let ray: Ray = new Ray(tileSpher.center, vectorFromTileToCamera);
        // let closetPointA = new Vector3(); //从瓦片包围球到相机位置最近的点
        // closetPointA = ray.intersectSphere(tileSpher, closetPointA);

        let elipsoidCenter = Config.Ellipsoid.center;
        // let vectorA = closetPointA.clone().sub(elipsoidCenter).normalize();

        // let vectorB = cameraPoint.clone().sub(elipsoidCenter).normalize();
        // let angle = vectorA.angleTo(vectorB);
        // let isTure1 = false;

        // //优化点：得到瓦片中心位置到地球球心的向量C，得到相机在地球上的sightPoint到相机位置的向量D，判断C向量和D向量是否指向同一个方向，如果同一个方向就没有被遮挡，否则就是被遮挡
        // if (angle < Math.PI / 2) {
        //     isTure1 = true;
        //     return true; //没有被遮挡
        // } else {
        //     isTure1 = false;
        //     return false;
        // }

        
        //要判断出该瓦片是否被地球遮挡了，可以从地球的球心向瓦片的中心点发射出一条射线，计算出这条射线和瓦片球体的相交点，用最远的相交点向相机的位置发射一条射线，计算出该射线是否和地球有相交点，如果没有，就说明该瓦片没有被地球遮挡，反之，就说明该瓦片被球体遮挡了
        let ellipsoid: Ellipsoid = Config.Ellipsoid;
        // let elipsoidCenter = Config.Ellipsoid.center;
        let vectorC = tileSpher.center.clone().sub(elipsoidCenter).normalize();
        let rayC: Ray = new Ray(tileSpher.center, vectorC);
        let intersectPointA = new Vector3();
        let clonedTileSpher = tileSpher.clone();
        clonedTileSpher.radius = clonedTileSpher.radius * 2;
        intersectPointA = rayC.intersectSphere(clonedTileSpher, intersectPointA);

        // let cameraPoint = camera.position.clone();
        let vectorD = cameraPoint.sub(intersectPointA).normalize();
        let rayD:Ray = new Ray(intersectPointA, vectorD);
        let intersectionArray = ellipsoid.intersectRay(rayD);
        if((intersectionArray == null || intersectionArray.length == 0)){ // && isTure1
            return true
        }
        return false;
    }

    /**检测瓦片是否被地球遮挡 */
    public static checkCover2(tileSpher: Sphere, camera: PerspectiveCamera) {
        let cameraPosition = camera.position.clone();

        let vectorFromTileToCamera = cameraPosition.clone().sub(tileSpher.center).normalize().multiplyScalar(1);
        let ray: Ray = new Ray(tileSpher.center, vectorFromTileToCamera);
        let closetPointA = new Vector3(); //从瓦片包围球到相机位置最近的点
        closetPointA = ray.intersectSphere(tileSpher, closetPointA);

        // Ellipsoid radii - WGS84 shown here
        let ellipsoid: Ellipsoid = Config.Ellipsoid;
        var rX = ellipsoid.radii.x;
        var rY = ellipsoid.radii.y;
        var rZ = ellipsoid.radii.z;

        // Vector CV
        var cvX = cameraPosition.x / rX;
        var cvY = cameraPosition.y / rY;
        var cvZ = cameraPosition.z / rZ;

        var vhMagnitudeSquared = cvX * cvX + cvY * cvY + cvZ * cvZ - 1.0;

        let position = closetPointA; //tileSpher.center.clone();
        // Target position, transformed to scaled space
        var tX = position.x / rX;
        var tY = position.y / rY;
        var tZ = position.z / rZ;

        // Vector VT
        var vtX = tX - cvX;
        var vtY = tY - cvY;
        var vtZ = tZ - cvZ;
        var vtMagnitudeSquared = vtX * vtX + vtY * vtY + vtZ * vtZ;

        // VT dot VC is the inverse of VT dot CV
        var vtDotVc = -(vtX * cvX + vtY * cvY + vtZ * cvZ);

        var isOccluded = vtDotVc > vhMagnitudeSquared &&
            vtDotVc * vtDotVc / vtMagnitudeSquared > vhMagnitudeSquared;

        if (isOccluded) {
            return false;
        }
        return true;
    }
}